<?php
/*++
 *功能：主要跟系统相关操作类
 *作者：gsj
 *时间：2012.7.25
 *描述：此类包括对INI配置文件的读取，修改，以及其他一些网络操作
 *文件名称：sys.class.php
--*/

class Sys {

	var $_file; //要获取的配置文件（绝对路径）
	var $_data = array(); //最终结果保存在此数组中
	
	var $_section;  //中间过程用于保存数组键名

	/*++
	 *函数名：_inifile
	 *作者：gsj
	 *时间：2012.07.25
	 *描述：读取配置文件信息到成员变量$_data数组中
	 *参数：保存配置文件的绝对路径的字符串
	 *返回值：返回保存结果的数组
	--*/
	function iniFile( $file = null )
	{
		if($file)
		{
			$this->_file = $file;

			if(!$fp = @fopen($this->_file, 'r')){
				$this->halt($file."配置文件未找到");
			}
			while ($data = fgets($fp, 4096))
			{
				$this->_ini($data);
			}
			fclose($fp);
		}
		return $this->_data;	
	}
	
	/*++
	 *函数名：_ini
	 *作者：gsj
	 *时间：2012.07.25
	 *描述：处理每一行的ini文件信息
	 *参数：ini配置的每一行字符串
	 *返回值：返回保存结果的数组
	--*/
	function _ini($data) 
	{

		$data = trim($data);//去掉空白

		if(empty($data) || substr($data, 0, 1) == ';') //为空或者为;注释的行
		{
			return;
		}

		// section
		if((substr($data, 0, 1) == "[") AND (substr($data, -1) == "]"))
		{
			$data = str_replace("[","",$data);
			$data = str_replace("]","",$data);
			$this->_section = $data;

			return;
		}
        // entry
        $pos = strpos($data, '=');  //= 第一次出现的位置
        if ($pos !== FALSE) { // boolean false
			// set name
			$name = trim(substr($data, 0, $pos));
			
			// set value
			$value = substr ($data, ($pos + 1), (strlen($data) - $pos - 1));
			
			// check for comma's and spaces in value, if so make array of it
			if (strpos($value, ", ")) {
				$list = explode (",", $value);
			
				// unset value
				$value = array();
			
				// loop through values and add them to array
				foreach ($list as $val) {
					$value[] = trim($val);
				}
			}
	
			// store value
			if($this->_section || $this->_section === '0')
			{
				$this->_data[$this->_section][$name] = $value;
			}
			else
			{
				$this->_data[$name] = $value;
			}
		}
			return $this->_data;
	}
	
	/*++
	 *函数名：addData
	 *作者：gsj
	 *时间：2012.07.25
	 *描述：向ini文件添加数据
	 *参数：文件绝对路径，方括号中的主键，一组数组的字符串
	 *返回值：成功返回true，否则返回false
	--*/
	function addData($file,$keyname,$str){
		$str = "[$keyname]\n$str\n";
		if(@file_put_contents($file,$str,FILE_APPEND)){
			return true;
		}else{
			return false;
		}
	}
	
	/*++
	 *函数名：delData
	 *作者：gsj
	 *时间：2012.07.25
	 *描述：删除ini文件相关数据
	 *参数：文件绝对路径，方括号中的主键
	 *返回值：成功返回true，否则返回false
	--*/
	function delData($file,$sep){
		$str = file_get_contents($file);

		if(is_string($sep) || is_int($sep)){ //为字符串或者整形，删除单个数据
			if(!$locate1 = strpos($str,"[$sep]")){
			    if($locate1 !== 0){
			        $this->halt("parameter error");
			    }
			}
			if(!$locate2 =strpos($str,"\n[",$locate1)){
			    $str = substr_replace($str,"",$locate1);
			    if(@file_put_contents($file,$str) >= 0){
			    	return true;
			    }else{
			    	return false;
			    };
			}else{
			    $len = $locate2-$locate1;
			    $str = substr_replace($str,"",$locate1,$len+1);
			    if(@file_put_contents($file,$str) >= 0){
			    	return true;
			    }else{
			    	return false;
			    };
			}
		}elseif(is_array($sep)){ //为数组，批量删除数据
			foreach($sep as $val){
				if(!$locate1 = strpos($str,"[$val]")){
				    if($locate1 !== 0){
				        $this->halt("parameter error");
				    }
				}
				if(!$locate2 =strpos($str,"\n[",$locate1)){
				    $str = substr_replace($str,"",$locate1);
				}else{
				    $len = $locate2-$locate1;
				    $str = substr_replace($str,"",$locate1,$len+1);
				}
			}
			$putlen = @file_put_contents($file,$str);
			if($putlen === 0 || $putlen>0){
				return true;
			}else{
				return false;
			}
		}
		
	}
	
	/*++
	 *函数名：updateDataType1
	 *作者：gsj
	 *时间：2012.07.25
	 *描述：更新ini文件相关项,需要方括号中的内容，即$sep，
	 *		$value1 为-1时做所有$key= 的替换，不为-1时做$key=$value1的替换
	 *参数：文件绝对路径，方括号中的主键，匹配键，原来值，新值
	 *返回值：成功返回true，否则返回false
	--*/
	function updateDataType1($file,$sep,$key,$value1,$value2){
		
	    $str = file_get_contents($file);
	    
	    if(is_string($sep) || is_int($sep)){//一组数据的更新
		    $arr = explode("[$sep]",$str);
		    if(count($arr)>1){
		    	//此处不考虑一组数据下出现相同$value1=$value2的情况，即只做一次替换
		    	if($value1 === -1){
			    	$arr[1] = preg_replace('/'.$key.'=(.*)/',$key.'='.$value2,$arr[1],1); 
		    	}else{
		    		$arr[1] = preg_replace('/'.$key.'='.$value1.'\n/',$key.'='.$value2."\n",$arr[1],1);
		    	}
			    $str = $arr[0]."[$sep]".$arr[1];
			    if(@file_put_contents($file,$str)){
			    	return true;
			    }else{
			    	return false;
			    }
		    }else{
		    	$this->halt("parameter error");
		    }
	    }elseif(is_array($sep)){ //多组数据的更新
	    	foreach($sep as $val){
	    		$arr = explode("[$val]",$str);
			    if(count($arr)>1){
			    	//此处不考虑一组数据下出现相同$value1=$value2的情况，即只做一次替换
			    	if($value1 === -1){  
				    	$arr[1] = preg_replace('/'.$key.'=(.*)/',$key.'='.$value2,$arr[1],1);
			    	}else{
			    		$arr[1] = preg_replace('/'.$key.'='.$value1.'\n/',$key.'='.$value2."\n",$arr[1],1);
			    	}
				    $str = $arr[0]."[$val]".$arr[1];
			    }else{
			    	$this->halt("parameter error");
			    }
	    	}
	    	$putlen = @file_put_contents($file,$str);
	    	if($putlen>0){
				return true;
			}else{
				return false;
			}
	    }    
	}
	
	/*++
	 *函数名：updateDataType1
	 *作者：gsj
	 *时间：2012.07.26
	 *描述：更新ini文件相关项,不要需要方括号中的内容，对文件中所有行进行匹配
	 *		$newkey属性名，$value1属性原来值，$value2新值
	 *参数：文件绝对路径，匹配键，原来值，新值
	 *返回值：成功返回true，否则返回false
	--*/
	function updateDataType2($file,$newkey,$value1,$value2) {
		$result = file_get_contents($file);
		//$pararr = array($newkey,$value1,$value2);
		//array_walk($result,"_arraychange",$pararr);
        if(preg_match("/$newkey=$value1\n/",$result,$match))
        {
            $result = preg_replace('/'.$newkey.'='.$value1.'\n/',$newkey.'='.$value2."\n",$result);
        }
        //原来的值中带|的情形
        /*if(preg_match("/$newkey=$value1(\|.*)+/",$result,$match))
        {
            if($value2 == "")
            {
                $replace_str = str_replace("$value1|","",$match[0]);
            }
            else
            {
                $replace_str = str_replace("$value1|","$value2|",$match[0]);
            }
            $result = preg_replace("/$newkey=$value1(\|.*)+\n/",$replace_str."\n",$result);
        }
        if(preg_match("/$newkey=(.*\|)+$value1(\|.*)+/",$result,$match))
        {
            if($value2 == "")
            {
                $replace_str = str_replace("$value1|","",$match[0]);
            }
            else
            {
                $replace_str = str_replace("$value1|","$value2|",$match[0]);
            }
            $result = preg_replace("/$newkey=(.*\|)+$value1(\|.*)+\n/",$replace_str."\n",$result);
            
        }
        if(preg_match("/$newkey=(.*\|)+$value1/",$result,$match))
        {
            if($value2 == "")
            {
                $replace_str = str_replace("|$value1","",$match[0]);
            }
            else
            {
                $replace_str = str_replace("|$value1","|$value2",$match[0]);
            }
            $result = preg_replace("/$newkey=(.*\|)+$value1\n/",$replace_str."\n",$result);
        }*/
		if(@file_put_contents($file, $result)>0){
			return true;
		}else{
			return false;
		}
	}
	
	/*++
	 *函数名：updateDataType3
	 *作者：gsj
	 *时间：2012.08.15
	 *描述：批量修改多个$sep下多个$key对应的值，不考虑原来的值,
	 *		$sep,$key_arr,$value_arr均为数组格式,且$key_arr,$value_arr中元素各种相同
	 *参数：文件绝对路径，主键值数组，匹配键数组，替换值数组
	 *返回值：成功返回true，否则返回false
	--*/
	function updateDataType3($file,$sep,$key_arr,$value_arr){
		if(count($key_arr) != count($value_arr)){
			$this->halt($file."parameter error");
		}elseif(!is_array($sep)){
			$this->halt($file."parameter error");
		}
	    $str = file_get_contents($file);

	    foreach($sep as $val){
	    	$arr = explode("[$val]",$str);
		    if(count($arr)>1){
				for($i = 0;$i<count($key_arr);$i++){
		    		$arr[1] = preg_replace('/'.$key_arr[$i].'=(.*)/',$key_arr[$i].'='.$value_arr[$i],$arr[1],1);
				}
			    $str = $arr[0]."[$val]".$arr[1];
		    }else{
		    	$this->halt("parameter error");
		    }
	    }
	    $putlen = @file_put_contents($file,$str);
	    if($putlen>0){
			return true;
		}else{
			return false;
		}
	}
	
	/*++
	 *函数名：updateDataType4
	 *作者：gsj
	 *时间：2012.08.15
	 *描述：批量修改多个$sep下多个$key对应的值，不考虑原来的值,
	 *		$sep,$key_arr,$value_arr均为数组格式,且$key_arr,$value_arr中元素各种相同
	 *		此种情况下$sep的值也会被更改，仅应用于更新单个工作站时
	 *参数：文件绝对路径，主键值数组，新的主键值数组，匹配键数组，替换值数组
	 *返回值：成功返回true，否则返回false
	--*/
	function updateDataType4($file,$sep,$newsep,$key_arr,$value_arr){
		if(count($key_arr) != count($value_arr)){
			$this->halt($file."parameter error");
		}elseif(count($sep) != count($newsep)){
			$this->halt($file."parameter error");
		}
	    $str = file_get_contents($file);

	    for($j = 0;$j<count($sep);$j++){
	    	$arr = explode("[".$sep[$j]."]",$str);
		    if(count($arr)>1){
				for($i = 0;$i<count($key_arr);$i++){
		    		$arr[1] = preg_replace('/'.$key_arr[$i].'=(.*)/',$key_arr[$i].'='.$value_arr[$i],$arr[1],1);
				}
			    $str = $arr[0]."[".$newsep[$j]."]".$arr[1];
		    }else{
		    	$this->halt("parameter error");
		    }
	    }
	    $putlen = @file_put_contents($file,$str);
	    if($putlen>0){
			return true;
		}else{
			return false;
		}
	}
		
	/*++
	 *函数名：size
	 *作者：gsj
	 *时间：2012.08.15
	 *描述：获取流量大小，将数值转换为对应单位的大小，精确到小数点后2位
	 *参数：流量大小
	 *返回值： 返回对应单位的流量值
	--*/
    function size($size)
    {
    	$i=0;
        $iec = array("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB");
        while (($size / 1024)>1)
        {
             $size = $size / 1024;
             $i++;
        }
        return substr($size,0,strpos($size,'.')+2).$iec[$i];
    }
    
    /*++
	 *函数名：live
	 *作者：gsj
	 *时间：2012.08.15
	 *描述：根据IP获取获取其MAC地址列表，iP可传入多个，中间用空格分割,linux下使用，需要安装nmap工具
	 *参数：IP地址
	 *返回值： 返回对应IP的一行记录
	--*/
	function live($ip)
	{
		$cmd = exec("nmap -sP $ip|grep MAC");

		if($cmd)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	/*++
	 *函数名：getClientIp
	 *作者：gsj
	 *时间：2012.08.15
	 *描述：获取客户端IP地址
	 *参数：无
	 *返回值： 返回登录web的客户端IP地址
	--*/ 
	function getClientIp(){ 
	    if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) 
	        $ip = getenv("HTTP_CLIENT_IP"); 
	    else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")) 
	        $ip = getenv("HTTP_X_FORWARDED_FOR"); 
	    else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")) 
	        $ip = getenv("REMOTE_ADDR"); 
	    else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) 
	        $ip = $_SERVER['REMOTE_ADDR']; 
	    else 
	        $ip = "unknown"; 
	    return($ip); 
	}
	
	/*++
	 *函数名：nmap
	 *作者：gsj
	 *时间：2012.08.15
	 *描述：根据IP获取获取存活主机列表，iP可传入多个，中间用空格分割
	 *参数：IP地址
	 *返回值： 返回存活的IP数组
	--*/
	function nmap($ip)
	{
		$cmd = `/usr/bin/nmap -sP -n $ip |grep 'appears to be up'|awk '{print $2}'`;
		if($cmd != ""){
			$cmd = split("\n",$cmd);
			if(count($cmd)>1){
				array_pop($cmd);
				return $cmd;
			}else{
				return false;
			}
		}else{
			return false;
		}
	}
	
	/*++
	 *函数名：halt
	 *作者：gsj
	 *时间：2012.08.15
	 *描述：停止运行脚本，数组错误提示信息
	 *参数：需要输出的错误信息
	 *返回值： 无
	--*/
	function halt($msg){
		die($msg);
	}
}

//改变数组内容，$pararr中依次为属性名，属性原来值，新值
function _arraychange(&$value,$key,$pararr) {
	//$value = preg_replace('/'.$pararr[0].'='.$pararr[1].'\n/',$pararr[0].'='.$pararr[2]."\n",$value,1);
	$val = explode("=",$value);
	if(count($val)>1){  //是否带=的属性加值的项
		$val_new = explode("|",$val[1]);
		if(count($val_new)==1){   //值 不带|
			$value = preg_replace('/'.$pararr[0].'='.$pararr[1].'\n/',$pararr[0].'='.$pararr[2]."\n",$value,1);
		}elseif(count($val_new)>1){	//值带|
			if($val[0] == $pararr[0]){ //是否是想要更改的属性
				foreach($val_new as $val_ret){  //遍历|分割后的所有数组,将符合条件的值替换为新值
					$val_ret = preg_replace('/'.$pararr[1].'/',$pararr[2],$val_ret,1);
					if(!empty($val_ret)){ //如果结果不为空，放到新数组里
						$arr[] = $val_ret;
					}
				}
				$value = $val[0].'='.@implode("|",$arr);
			}else{
				return;
			}
		}else{
			return;
		}
	}else{
		return;
	}
}
?>